package com.alibaba.dubbo.remoting.msgcodec;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.GZIPOutputStream;

import com.alibaba.dubbo.common.configure.ExtensionConfiguratorUtils;
import com.alibaba.dubbo.remoting.MessageEncode;

public class GZipEncode implements MessageEncode {
	private static final int BUFFER = 8*1024;
	private static final int THRESHOLD = 4096;
	
	public GZipEncode(){
		threshold = ExtensionConfiguratorUtils.getInstance().getIntValue(
				ExtensionConfiguratorUtils.combine(GZipEncode.class, "threashold"), THRESHOLD); 
		deflate = ExtensionConfiguratorUtils.getInstance().getBooleanValue(
				ExtensionConfiguratorUtils.combine(GZipEncode.class, "deflate"), false); 
	}
	
	private int threshold = THRESHOLD;
	
	public int getThreshold() {
		return threshold;
	}

	public void setThreshold(int threshold) {
		this.threshold = threshold;
	}
	
	
	private boolean deflate = false;
	
	public boolean isDeflate() {
		return deflate;
	}

	public void setDeflate(boolean deflate) {
		this.deflate = deflate;
	}

	@Override
	public int encode(InputStream in, OutputStream out/*, MessageEncodeRegistry registry*/) throws IOException {
		int length  = in.available();
		if(threshold > 0 && length < threshold){
			out.write(0);
			byte [] data = new byte[length];
			int len = in.read(data);
			out.write(data, 0, len);
			return len;
		}else if(!deflate){
			out.write(1);
			//ByteArrayOutputStream baos = new ByteArrayOutputStream();  
			GZIPOutputStream gos = new GZIPOutputStream(out);
	
			int count;
			byte data[] = new byte[BUFFER];
			int n = 0;
			while ((count = in.read(data, 0, BUFFER)) != -1) {
				gos.write(data, 0, count);
				n += count;
			}
	
			gos.finish();
			//gos.flush();
			//gos.close();
			
			//byte [] os = baos.toByteArray();
			//out.write(os);
			/*
			if(registry != null){
				registry.appendEncode("gzip");
			}
			*/
			//return os.length;
			return n;
		}else{
			out.write(2);
			//ByteArrayOutputStream baos = new ByteArrayOutputStream();  
			DeflaterOutputStream gos = new DeflaterOutputStream(out);
	
			int count;
			int n = 0;
			byte data[] = new byte[BUFFER];
			while ((count = in.read(data, 0, BUFFER)) != -1) {
				gos.write(data, 0, count);
				n += count;
			}
	
			gos.finish();
			//gos.flush();
			//gos.close();
			
			//byte [] os = baos.toByteArray();
			//out.write(os);
			/*
			if(registry != null){
				registry.appendEncode("gzip");
			}
			*/
			//return os.length;
			return n;
		}
	}

	static public void main(String []args) throws IOException{
		byte[] data = "threshold = ExtensionConfiguratorUtils.getInstance().getIntValue(ExtensionConfiguratorUtils.combine(GZipEncode.class, \"threashold\"), THRESHOLD);".getBytes("UTF-8");
		InputStream in = new ByteArrayInputStream(data);
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		
		GZipEncode encoder = new GZipEncode();
		encoder.setThreshold(0);
		encoder.setDeflate(true);
		encoder.encode(in, out);
		
		GZipDecode decoder = new GZipDecode(); 
		
		in = new ByteArrayInputStream(out.toByteArray());
		out.reset();
		decoder.decode(in, out);
		System.out.println(out.toString("UTF-8"));
	}
}
